package com.demo.java.OD401_450.OD440;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author bug菌
 * @Source 公众号：猿圈奇妙屋
 * @des： 【符号运算(C&D卷-200分)】问题
 * @url： https://blog.csdn.net/weixin_43970743/article/details/146325807
 */
public class OdMain {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);  // 创建扫描器对象来读取控制台输入

        // 提示用户输入数学表达式
        System.out.print("请输入数学表达式：");
        String s = scanner.nextLine();  // 读取用户输入的表达式

        try {
            Object tmp = customEval(s);  // 计算结果

            if (tmp instanceof Integer) {
                System.out.println(tmp);  // 输出整数结果
            } else if (tmp instanceof Double) {
                System.out.println(limitDenominatorCustom((Double) tmp));  // 输出分数结果
            } else {
                System.out.println("ERROR");  // 错误输出
            }
        } catch (ArithmeticException e) {
            System.out.println("ERROR");  // 除零错误时输出ERROR
        } finally {
            scanner.close();  // 关闭扫描器
        }
    }

    private static Map<String, Operator> operators = new HashMap<>();

    static {
        // 定义操作符及其优先级
        operators.put("+", new Operator(1, (x, y) -> x + y));
        operators.put("-", new Operator(1, (x, y) -> x - y));
        operators.put("*", new Operator(2, (x, y) -> x * y));
        operators.put("/", new Operator(2, (x, y) -> x / y));  // 除法
    }

    private static class Operator {
        int precedence;
        BinaryOperation operation;

        Operator(int precedence, BinaryOperation operation) {
            this.precedence = precedence;
            this.operation = operation;
        }
    }

    private static interface BinaryOperation {
        double apply(double x, double y);
    }

    // 自定义表达式计算
    private static double customEval(String expression) {
        Deque<Object> output = new ArrayDeque<>();
        Deque<String> stack = new ArrayDeque<>();

        expression = expression.replaceAll(" ", "");  // 移除表达式中的空格

        if (!expression.matches("^[ \\d+\\-*/\\(\\)]+$")) {
            throw new IllegalArgumentException("Error");
        }

        Pattern pattern = Pattern.compile("(\\d+\\.?\\d*|\\+|\\-|\\*|/|\\(|\\))");
        Matcher matcher = pattern.matcher(expression);

        while (matcher.find()) {
            String token = matcher.group();

            if (token.matches("^-?\\d+(\\.\\d+)?$")) {
                output.add(Double.parseDouble(token));  // 如果是数字，则加入输出栈
            } else if (operators.containsKey(token)) {
                while (!stack.isEmpty() && operators.containsKey(stack.peek()) &&
                        operators.get(token).precedence <= operators.get(stack.peek()).precedence) {
                    output.add(stack.pop());  // 处理操作符的优先级
                }
                stack.push(token);  // 加入当前操作符
            } else if ("(".equals(token)) {
                stack.push(token);  // 左括号入栈
            } else if (")".equals(token)) {
                while (!stack.isEmpty() && !"(".equals(stack.peek())) {
                    output.add(stack.pop());  // 右括号时弹出操作符
                }
                stack.pop();  // 弹出左括号
            }
        }

        while (!stack.isEmpty()) {
            output.add(stack.pop());  // 弹出剩余的操作符
        }

        Deque<Double> evaluationStack = new ArrayDeque<>();

        for (Object token : output) {
            if (token instanceof Double) {
                evaluationStack.push((Double) token);  // 如果是数字，压栈
            } else if (token instanceof String && operators.containsKey(token)) {
                double y = evaluationStack.pop();
                double x = evaluationStack.pop();
                Operator operator = operators.get(token);
                evaluationStack.push(operator.operation.apply(x, y));  // 执行运算
            }
        }

        return evaluationStack.pop();  // 返回最终结果
    }

    // 将浮动小数转化为最简分数
    private static String limitDenominatorCustom(double value, int maxDenominator) {
        if (value == (int) value) {
            return Integer.toString((int) value);  // 如果是整数，直接输出
        }

        int bestNumerator = 0;
        int bestDenominator = 1;
        double bestError = Math.abs(value - bestNumerator / (double) bestDenominator);

        for (int denominator = 1; denominator <= maxDenominator; denominator++) {
            int numerator = (int) Math.round(value * denominator);
            double error = Math.abs(value - numerator / (double) denominator);

            if (error < bestError) {
                bestNumerator = numerator;
                bestDenominator = denominator;
                bestError = error;
            }
        }

        if (bestDenominator == 1) {
            return Integer.toString(bestNumerator);  // 如果分母是1，返回整数
        }

        return bestNumerator + "/" + bestDenominator;  // 返回分数
    }

    private static String limitDenominatorCustom(double value) {
        return limitDenominatorCustom(value, 1000000);  // 默认最大分母
    }
}
